#!/usr/bin/env node

/**
 * Phase5 静态代码分析工具
 * 执行TypeScript编译、ESLint检查、依赖验证等静态分析
 */

const fs = require('fs');
const path = require('path');
const { exec } = require('child_process');
const { promisify } = require('util');
const execAsync = promisify(exec);

class StaticAnalyzer {
  constructor(componentName) {
    this.componentName = componentName;
    this.results = {
      typescript: null,
      eslint: null,
      imports: null,
      circular: null,
      passed: false
    };
  }

  /**
   * 执行TypeScript编译检查
   */
  async runTypeScriptCheck() {
    const files = [
      'src/components/editor/schema/fields/aiComponents.ts',
      'src/components/editor/schema/edit/aiComponents.ts',
      `src/components/editor/schema/preview/components/${this.componentName}/index.tsx`
    ];

    try {
      for (const file of files) {
        if (!fs.existsSync(file)) {
          throw new Error(`Missing file: ${file}`);
        }
      }

      const hasPhaseConfig = fs.existsSync('tsconfig.phase5.json');
      const tscCommand = hasPhaseConfig
        ? 'npx tsc --noEmit -p tsconfig.phase5.json'
        : `npx tsc --noEmit ${files.join(' ')}`;

      const { stdout } = await execAsync(tscCommand);

      this.results.typescript = {
        passed: true,
        output: stdout || 'No TypeScript errors'
      };
    } catch (error) {
      const diagnostics = (error.stderr || error.stdout || '').split('\n').filter(Boolean);
      const relevantDiagnostics = diagnostics.filter((line) =>
        files.some((file) => line.includes(file))
      );

      if (relevantDiagnostics.length === 0) {
        this.results.typescript = {
          passed: true,
          warning: 'TypeScript reported existing project issues unrelated to the current component.'
        };
      } else {
        this.results.typescript = {
          passed: false,
          error: error.message,
          details: relevantDiagnostics.join('\n') || diagnostics.join('\n')
        };
      }
    }
  }

  /**
   * 执行ESLint增量检查
   */
  async runESLintIncremental() {
    try {
      // 获取最近修改的文件
      const { stdout: gitFiles } = await execAsync('git diff --name-only --relative HEAD~1 HEAD -- "*.ts" "*.tsx"');
      const files = gitFiles
        .split('\n')
        .map(file => file.trim())
        .filter(file => file && fs.existsSync(file));

      if (files.length === 0) {
        this.results.eslint = {
          passed: true,
          message: 'No files to lint'
        };
        return;
      }

      // 执行ESLint
      const { stdout, stderr } = await execAsync(`npx eslint ${files.join(' ')} --format json`);
      const report = JSON.parse(stdout);

      const hasErrors = report.some(file => file.errorCount > 0);
      const hasWarnings = report.some(file => file.warningCount > 0);

      this.results.eslint = {
        passed: !hasErrors,
        errorCount: report.reduce((sum, file) => sum + file.errorCount, 0),
        warningCount: report.reduce((sum, file) => sum + file.warningCount, 0),
        files: report.length
      };
    } catch (error) {
      // ESLint返回非零退出码表示有错误
      if (error.stdout) {
        try {
          const report = JSON.parse(error.stdout);
          this.results.eslint = {
            passed: false,
            errorCount: report.reduce((sum, file) => sum + file.errorCount, 0),
            warningCount: report.reduce((sum, file) => sum + file.warningCount, 0),
            details: report
          };
        } catch {
          this.results.eslint = {
            passed: false,
            error: error.message
          };
        }
      } else {
        this.results.eslint = {
          passed: false,
          error: error.message
        };
      }
    }
  }

  /**
   * 验证导入依赖
   */
  async validateImports() {
    const previewFile = `src/components/editor/schema/preview/components/${this.componentName}/index.tsx`;

    try {
      const content = fs.readFileSync(previewFile, 'utf8');
      const importRegex = /import\s+(?:.*?\s+from\s+)?['"]([^'"]+)['"]/g;
      const imports = [];
      let match;

      while ((match = importRegex.exec(content)) !== null) {
        imports.push(match[1]);
      }

      // 检查关键导入
      const requiredImports = ['react'];
      const missingImports = requiredImports.filter(req => !imports.some(imp => imp.includes(req)));

      // 检查相对路径导入的文件存在性
      const relativeImports = imports.filter(imp => imp.startsWith('.'));
      const invalidImports = [];

      for (const imp of relativeImports) {
        const resolvedPath = path.resolve(path.dirname(previewFile), imp);
        const possiblePaths = [
          resolvedPath,
          `${resolvedPath}.ts`,
          `${resolvedPath}.tsx`,
          `${resolvedPath}/index.ts`,
          `${resolvedPath}/index.tsx`
        ];

        if (!possiblePaths.some(p => fs.existsSync(p))) {
          invalidImports.push(imp);
        }
      }

      this.results.imports = {
        passed: missingImports.length === 0 && invalidImports.length === 0,
        totalImports: imports.length,
        missingRequired: missingImports,
        invalidPaths: invalidImports
      };
    } catch (error) {
      this.results.imports = {
        passed: false,
        error: error.message
      };
    }
  }

  /**
   * 检查循环依赖
   */
  async checkCircularDependencies() {
    try {
      // 使用madge检查循环依赖
      const { stdout } = await execAsync(`npx madge --circular src/components/editor/schema/preview/components/${this.componentName}/index.tsx --json`);
      const result = JSON.parse(stdout);

      this.results.circular = {
        passed: result.length === 0,
        circularDeps: result
      };
    } catch (error) {
      // 如果madge未安装，跳过检查
      if (error.message.includes('madge')) {
        this.results.circular = {
          passed: true,
          skipped: true,
          message: 'Circular dependency check skipped (madge not installed)'
        };
      } else {
        this.results.circular = {
          passed: false,
          error: error.message
        };
      }
    }
  }

  /**
   * 执行所有静态分析
   */
  async runAll() {
    console.log('Starting static analysis...');

    await this.runTypeScriptCheck();
    console.log('✓ TypeScript check completed');

    await this.runESLintIncremental();
    console.log('✓ ESLint check completed');

    await this.validateImports();
    console.log('✓ Import validation completed');

    await this.checkCircularDependencies();
    console.log('✓ Circular dependency check completed');

    // 判断整体是否通过
    this.results.passed = Object.values(this.results)
      .filter(r => r && typeof r === 'object')
      .every(r => r.passed);

    return this.results;
  }

  /**
   * 生成报告
   */
  generateReport() {
    const report = {
      timestamp: new Date().toISOString(),
      component: this.componentName,
      staticAnalysis: this.results,
      summary: {
        passed: this.results.passed,
        checks: {
          typescript: this.results.typescript?.passed ? 'PASS' : 'FAIL',
          eslint: this.results.eslint?.passed ? 'PASS' : 'FAIL',
          imports: this.results.imports?.passed ? 'PASS' : 'FAIL',
          circular: this.results.circular?.passed ? 'PASS' : 'FAIL'
        }
      }
    };

    // 保存报告
    const reportDir = path.join(this.componentName, 'phase5');
    const reportPath = path.join(reportDir, 'static-analysis-report.json');
    fs.mkdirSync(reportDir, { recursive: true });
    fs.writeFileSync(reportPath, JSON.stringify(report, null, 2));

    console.log(`\n📊 Static Analysis Report saved to: ${reportPath}`);

    return report;
  }
}

// CLI执行
if (require.main === module) {
  const componentName = process.argv[2];

  if (!componentName) {
    console.error('Usage: node static-analysis.js <ComponentName>');
    process.exit(1);
  }

  const analyzer = new StaticAnalyzer(componentName);

  analyzer.runAll()
    .then(results => {
      const report = analyzer.generateReport();

      if (!results.passed) {
        console.error('\n❌ Static analysis failed');
        console.error('Details:', JSON.stringify(report.summary, null, 2));
        process.exit(1);
      } else {
        console.log('\n✅ Static analysis passed');
        process.exit(0);
      }
    })
    .catch(error => {
      console.error('\n❌ Static analysis error:', error.message);
      process.exit(1);
    });
}

module.exports = StaticAnalyzer;
